package com.http;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.CountDownLatch;

import org.apache.http.Consts;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.easysoft.commons.utils.JSONUtils;
import com.easysoft.commons.utils.StringUtils;

public class HttpAsynClient {

	private static final Logger logger = LoggerFactory.getLogger(HttpAsynClient.class);

	/**
	 * 批量异步执行GET请求
	 * 
	 * @param urls
	 *            请求地址
	 * @return {completed:1,failed:2,cancelled=3} 完成; 失败 ;取消
	 * @throws Exception
	 */
	public static String doGet(final List<String> urls) throws Exception {
		return doGet(urls, null, 0, null);
	}

	/**
	 * 批量异步执行GET请求
	 * 
	 * @param urls
	 *            请求地址
	 * @param hostname
	 *            网络代理服务器IP
	 * @param port
	 *            网络代理服务器端口
	 * @param scheme
	 *            网络代理类型：http
	 * @return {completed:1,failed:2,cancelled=3} 完成; 失败 ;取消
	 * @throws Exception
	 */
	public static String doGet(final List<String> urls, final String hostname, final int port, final String scheme) throws Exception {

		if (urls == null || urls.size() == 0) {
			return "";
		}

		HttpHost proxy = null;
		if (StringUtils.isNotNullAndBlank(hostname) && StringUtils.isNotNullAndBlank(scheme)) {
			proxy = new HttpHost(hostname, port, scheme);
		}

		RequestConfig config = RequestConfig.custom().setProxy(proxy).setSocketTimeout(5000).setConnectTimeout(5000)
				.setConnectionRequestTimeout(5000).setCircularRedirectsAllowed(true).build();

		CloseableHttpAsyncClient client = HttpAsyncClients.custom().setDefaultRequestConfig(config).setMaxConnTotal(1000)
				.setMaxConnPerRoute(1000).build();

		int size = urls.size();
		HttpGet[] requests = new HttpGet[size];
		for (int i = 0; i < size; i++) {
			requests[i] = new HttpGet(urls.get(i));
			requests[i].addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0");
		}

		final int[] count = new int[3];

		try {
			client.start();

			final CountDownLatch latch = new CountDownLatch(requests.length);
			for (final HttpGet request : requests) {

				logger.info("调用URI={}", request.getURI().getPath());

				client.execute(request, new FutureCallback<HttpResponse>() {


					public void completed(final HttpResponse response) {
						latch.countDown();
						count[0]++;
						logger.info(request.getRequestLine() + "->" + response.getStatusLine());
					}


					public void failed(final Exception ex) {
						latch.countDown();
						count[1]++;
						logger.warn(request.getRequestLine() + "->" + ex.getMessage());
					}


					public void cancelled() {
						latch.countDown();
						count[2]++;
						logger.info(request.getRequestLine() + "-> cancelled");
					}
				});
			}

			latch.await();
		}
		finally {
			client.close();
		}

		Map<String, String> result = new HashMap<String, String>();
		result.put("completed", String.valueOf(count[0]));
		result.put("failed", String.valueOf(count[1]));
		result.put("cancelled", String.valueOf(count[2]));

		return JSONUtils.object2Json(result);
	}

	/**
	 * 批量异步执行POST请求
	 * 
	 * @param url
	 *            请求地址
	 * @return {completed:1,failed:2,cancelled=3} 完成; 失败 ;取消
	 * @throws Exception
	 */
	public static String doPost(final String url, final List<Map<String, String>> parameters) throws Exception {
		return doPost(url, parameters, null, 0, null);
	}

	/**
	 * 批量异步执行POST请求
	 * 
	 * @param url
	 *            请求地址
	 *            网络代理服务器IP
	 * @param port
	 * @param hostname
	 *            网络代理服务器端口
	 * @param scheme
	 *            网络代理类型：http
	 * @return {completed:1,failed:2,cancelled=3} 完成; 失败 ;取消
	 * @throws Exception
	 */
	public static String doPost(final String url, final List<Map<String, String>> parameters, final String hostname, final int port,
			final String scheme) throws Exception {

		if (url == null || url.length() == 0) {
			return "";
		}

		HttpHost proxy = null;
		if (StringUtils.isNotNullAndBlank(hostname) && StringUtils.isNotNullAndBlank(scheme)) {
			proxy = new HttpHost(hostname, port, scheme);
		}

		RequestConfig config = RequestConfig.custom().setProxy(proxy).setSocketTimeout(5000).setConnectTimeout(5000)
				.setConnectionRequestTimeout(5000).setCircularRedirectsAllowed(true).build();

		CloseableHttpAsyncClient client = HttpAsyncClients.custom().setDefaultRequestConfig(config).setMaxConnTotal(1000)
				.setMaxConnPerRoute(1000).build();

		int size = parameters.size();
		HttpPost[] requests = new HttpPost[size];
		for (int i = 0; i < size; i++) {

			requests[i] = new HttpPost(url);
			requests[i].addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0");
			requests[i].setConfig(config);
			if (parameters != null) {
				List<NameValuePair> params = new ArrayList<NameValuePair>();
				for (Entry<String, String> parameter : parameters.get(i).entrySet()) {
					params.add(new BasicNameValuePair(parameter.getKey(), parameter.getValue()));
				}
				requests[i].setEntity(new UrlEncodedFormEntity(params, Consts.UTF_8));
			}
		}

		final int[] count = new int[3];

		try {
			client.start();

			final CountDownLatch latch = new CountDownLatch(requests.length);
			for (final HttpPost request : requests) {

				logger.info("调用URI={}", request.getURI().getPath());

				client.execute(request, new FutureCallback<HttpResponse>() {


					public void completed(final HttpResponse response) {
						latch.countDown();
						count[0]++;
						logger.info(request.getRequestLine() + "->" + response.getStatusLine());
					}


					public void failed(final Exception ex) {
						latch.countDown();
						count[1]++;
						logger.warn(request.getRequestLine() + "->" + ex.getMessage());
					}


					public void cancelled() {
						latch.countDown();
						count[2]++;
						logger.info(request.getRequestLine() + "-> cancelled");
					}
				});
			}

			latch.await();
		}
		finally {
			client.close();
		}

		Map<String, String> result = new HashMap<String, String>();
		result.put("completed", String.valueOf(count[0]));
		result.put("failed", String.valueOf(count[1]));
		result.put("cancelled", String.valueOf(count[2]));

		return JSONUtils.object2Json(result);
	}

	public static void main(String args[]) throws Exception {
		List<String> urls = new ArrayList<String>();
		urls.add("http://www.badu.com");
		urls.add("http://www.badu.com");
		urls.add("http://www.badu.com");
		urls.add("http://www.badu.com");
		System.out.println(HttpAsynClient.doGet(urls));
	}

}
